<template>
  <div id="app">
    <button @click="returnFn" class="btn btn-primary retrunBUtton">
      <i class="icon">⚡</i> 返回
    </button>
    <div class="container">
      <header>
        <h1>Base64编码/解码工具</h1>
        <p class="subtitle">在线Base64编码和解码，支持文本和文件</p>
      </header>

      <div class="main-content">
        <!-- 输入区域 -->
        <div class="input-section">
          <div class="section-title">
            <h2>输入内容</h2>
            <div class="button-group">
              <button @click="clearInput" class="btn btn-secondary">
                <i class="icon">🗑️</i> 清空
              </button>
            </div>
          </div>
          <textarea
            v-model="inputText"
            placeholder="在此输入要编码的文本或要解码的Base64字符串"
            class="input-area"
            :class="{ error: hasError }"
          ></textarea>

          <!-- 文件上传区域 -->
          <div class="file-upload">
            <label class="file-label">
              <input type="file" @change="handleFileUpload" class="file-input" ref="fileInput" />
              <span class="file-button"> <i class="icon">📁</i> 选择文件 </span>
              <span v-if="selectedFile" class="file-name">{{ selectedFile.name }}</span>
            </label>
          </div>

          <div v-if="hasError" class="error-message"><i class="icon">❌</i> {{ errorMessage }}</div>
        </div>

        <!-- 操作按钮 -->
        <div class="action-buttons">
          <button @click="encodeBase64" class="action-btn encode-btn">
            <i class="icon">🔒</i> 编码为Base64
          </button>
          <button @click="decodeBase64" class="action-btn decode-btn">
            <i class="icon">🔓</i> 解码Base64
          </button>
        </div>

        <!-- 输出区域 -->
        <div class="output-section">
          <div class="section-title">
            <h2>处理结果</h2>
            <div class="button-group">
              <button @click="copyToClipboard" class="btn btn-success" :disabled="!outputText">
                <i class="icon">📋</i> {{ copyButtonText }}
              </button>
              <button @click="clearOutput" class="btn btn-secondary">
                <i class="icon">🗑️</i> 清空
              </button>
            </div>
          </div>
          <div class="output-area">{{ outputText }}</div>

          <!-- 文件下载区域 -->
          <div v-if="isFileOutput" class="file-download">
            <button @click="downloadFile" class="btn btn-primary">
              <i class="icon">💾</i> 下载文件
            </button>
            <span class="file-info">文件类型: {{ fileType }}</span>
          </div>
        </div>
      </div>

      <footer>
        <p>Base64工具 v1.0 | 使用Vue 3开发</p>
      </footer>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
// 响应式数据
const inputText = ref('')
const outputText = ref('')
const hasError = ref(false)
const errorMessage = ref('')
const copyButtonText = ref('复制')
const selectedFile = ref(null)
const fileInput = ref(null)
const isFileOutput = ref(false)
const fileType = ref('')
const Router = useRouter()
// 计算属性
const inputIsBase64 = computed(() => {
  if (!inputText.value) return false
  // 简单的Base64格式检测
  const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/
  return base64Regex.test(inputText.value.replace(/\s/g, ''))
})
const returnFn = () => {
  Router.go(-1)
}
// 方法
const encodeBase64 = () => {
  if (!inputText.value.trim()) {
    showError('请输入要编码的内容')
    return
  }

  try {
    // 如果是文件，先读取文件内容
    if (selectedFile.value) {
      encodeFileToBase64(selectedFile.value)
    } else {
      // 文本编码
      const encoded = btoa(unescape(encodeURIComponent(inputText.value)))
      outputText.value = formatBase64(encoded)
      isFileOutput.value = false
      clearError()
    }
  } catch (error) {
    showError('编码失败: ' + error.message)
  }
}

const decodeBase64 = () => {
  if (!inputText.value.trim()) {
    showError('请输入要解码的Base64字符串')
    return
  }

  try {
    // 移除可能的格式化和空格
    const cleanBase64 = inputText.value.replace(/\s/g, '')

    // 检测是否是文件数据
    if (isLikelyFileData(cleanBase64)) {
      decodeBase64ToFile(cleanBase64)
    } else {
      // 文本解码
      const decoded = decodeURIComponent(escape(atob(cleanBase64)))
      outputText.value = decoded
      isFileOutput.value = false
      clearError()
    }
  } catch (error) {
    showError('解码失败: ' + error.message)
  }
}

const encodeFileToBase64 = (file) => {
  const reader = new FileReader()
  reader.onload = () => {
    // 移除data URL前缀，只保留Base64数据
    const base64 = reader.result.split(',')[1]
    outputText.value = formatBase64(base64)
    isFileOutput.value = false
    clearError()
  }
  reader.onerror = () => {
    showError('文件读取失败')
  }
  reader.readAsDataURL(file)
}

const decodeBase64ToFile = (base64String) => {
  try {
    // 尝试解码为二进制数据
    const binaryString = atob(base64String)
    const bytes = new Uint8Array(binaryString.length)

    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i)
    }

    // 检测文件类型
    const type = detectFileType(bytes)
    fileType.value = type || '未知类型'
    isFileOutput.value = true
    outputText.value = `检测到文件数据 (${fileType.value})，请点击下载按钮保存文件`
    clearError()

    // 保存Blob对象用于下载
    selectedFile.value = new Blob([bytes], { type: type || 'application/octet-stream' })
  } catch (error) {
    showError('文件解码失败: ' + error.message)
  }
}

const handleFileUpload = (event) => {
  const file = event.target.files[0]
  if (file) {
    selectedFile.value = file
    inputText.value = `文件: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`
    clearError()
  }
}

const downloadFile = () => {
  if (!selectedFile.value) return

  const url = URL.createObjectURL(selectedFile.value)
  const a = document.createElement('a')
  a.href = url
  a.download = `decoded_file.${getFileExtension(fileType.value)}`
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  URL.revokeObjectURL(url)
}

const copyToClipboard = async () => {
  if (!outputText.value) return

  try {
    await navigator.clipboard.writeText(outputText.value)
    copyButtonText.value = '已复制!'
    setTimeout(() => {
      copyButtonText.value = '复制'
    }, 2000)
  } catch (err) {
    console.error('复制失败: ', err)
    copyButtonText.value = '复制失败'
    setTimeout(() => {
      copyButtonText.value = '复制'
    }, 2000)
  }
}

const clearInput = () => {
  inputText.value = ''
  selectedFile.value = null
  if (fileInput.value) {
    fileInput.value.value = ''
  }
  clearError()
}

const clearOutput = () => {
  outputText.value = ''
  isFileOutput.value = false
}

const showError = (message) => {
  hasError.value = true
  errorMessage.value = message
}

const clearError = () => {
  hasError.value = false
  errorMessage.value = ''
}

const formatBase64 = (base64) => {
  // 每76个字符插入换行（符合RFC 2045标准）
  return base64.replace(/(.{76})/g, '$1\n')
}

const isLikelyFileData = (base64) => {
  // 简单的文件数据检测（基于长度和字符分布）
  return base64.length > 100 &&
    base64.length % 4 === 0 &&
    /^[A-Za-z0-9+/]+={0,2}$/.test(base64)
}

const detectFileType = (bytes) => {
  // 简单的文件类型检测
  if (bytes.length < 4) return null

  const signatures = {
    'ffd8ffe0': 'image/jpeg',
    '89504e47': 'image/png',
    '47494638': 'image/gif',
    '25504446': 'application/pdf',
    '504b0304': 'application/zip',
    '52494646': 'audio/wav',
    '66747970': 'video/mp4'
  }

  const hex = Array.from(bytes.slice(0, 4))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('')

  return signatures[hex] || null
}

const getFileExtension = (mimeType) => {
  const extensions = {
    'image/jpeg': 'jpg',
    'image/png': 'png',
    'image/gif': 'gif',
    'application/pdf': 'pdf',
    'application/zip': 'zip',
    'audio/wav': 'wav',
    'video/mp4': 'mp4'
  }

  return extensions[mimeType] || 'bin'
}
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

#app {
  min-height: 100vh;
  background: linear-gradient(135deg, #1a2a6c 0%, #b21f1f 50%, #fdbb2d 100%);
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
  position: relative;
}
.retrunBUtton {
  position: absolute;
  top: 100px;
  right: 100px;
}

.container {
  width: 100%;
  max-width: 1500px;
  background-color: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
  overflow: hidden;
}

header {
  background: linear-gradient(to right, #1a2a6c, #b21f1f);
  color: white;
  padding: 20px 30px;
  text-align: center;
}

h1 {
  font-size: 36px;
  margin-bottom: 5px;
}

.subtitle {
  font-size: 20px;
  opacity: 0.9;
}

.main-content {
  display: flex;
  flex-direction: column;
  padding: 25px;
}

.input-section,
.output-section {
  margin-bottom: 25px;
}

.section-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

.section-title h2 {
  font-size: 20px;
  color: #333;
}

.button-group {
  display: flex;
  gap: 10px;
}

.btn {
  padding: 8px 15px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 20px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 5px;
  transition: all 0.3s ease;
}

.btn-primary {
  background: linear-gradient(to right, #1a2a6c, #b21f1f);
  color: white;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(26, 42, 108, 0.3);
}

.btn-primary:disabled {
  background: #cccccc;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn-secondary {
  background: #f0f0f0;
  color: #333;
}

.btn-secondary:hover {
  background: #e0e0e0;
}

.btn-success {
  background: linear-gradient(to right, #00b09b, #96c93d);
  color: white;
}

.btn-success:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0, 176, 155, 0.3);
}

.input-area,
.output-area {
  width: 100%;
  min-height: 150px;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 8px;
  font-family: 'Courier New', monospace;
  font-size: 20px;
  resize: vertical;
  outline: none;
  transition: border-color 0.3s;
  white-space: pre-wrap;
  word-break: break-all;
}

.input-area:focus {
  border-color: #b21f1f;
}

.input-area.error {
  border-color: #e74c3c;
}

.output-area {
  background-color: #f9f9f9;
  resize: none;
}

.action-buttons {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin: 20px 0;
}

.action-btn {
  padding: 12px 25px;
  font-size: 20px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  transition: all 0.3s ease;
}

.encode-btn {
  background: linear-gradient(to right, #1a2a6c, #b21f1f);
  color: white;
}

.decode-btn {
  background: linear-gradient(to right, #00b09b, #96c93d);
  color: white;
}

.action-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}

footer {
  text-align: center;
  padding: 15px;
  background-color: #f5f5f5;
  color: #666;
  font-size: 20px;
}

.icon {
  font-style: normal;
}

.error-message {
  margin-top: 10px;
  padding: 10px;
  background-color: #ffeaea;
  border-left: 4px solid #e74c3c;
  color: #c0392b;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.file-upload {
  margin-top: 15px;
}

.file-input {
  display: none;
}

.file-label {
  display: flex;
  align-items: center;
  gap: 10px;
}

.file-button {
  padding: 8px 15px;
  background: #f0f0f0;
  border-radius: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 5px;
  transition: background 0.3s;
}

.file-button:hover {
  background: #e0e0e0;
}

.file-name {
  color: #666;
  font-size: 20px;
}

.file-download {
  margin-top: 15px;
  display: flex;
  align-items: center;
  gap: 15px;
}

.file-info {
  color: #666;
  font-size: 20px;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .section-title {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }

  .button-group {
    width: 100%;
    justify-content: flex-end;
  }

  .action-buttons {
    flex-direction: column;
  }
}
</style>